const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const RECJECTED = 'rejected'

class _Promise {
  PromiseState = PENDING
  PromiseResult = undefined
  fulfilledCallback = []
  rejectedCallback = []

  constructor(init) {
    // 捕获错误
    try {
      init(this.resolve.bind(this), this.recject.bind(this))
    } catch (error) {
      this.recject(error)
    }
  }

  resolve(val) {
    // 只有在 pending 时，才允许更改状态
    if (this.PromiseState === PENDING) {
      this.PromiseState = FULFILLED
      this.PromiseResult = val
      this.fulfilledCallback.forEach((callback) => callback())
    }
  }

  recject(error) {
    if (this.PromiseState === PENDING) {
      this.PromiseState = RECJECTED
      this.PromiseResult = error
      this.rejectedCallback.forEach((callback) => callback())
    }
  }

  then(onFulfilled, onRejected) {
    // 链式调用
    const promise = new _Promise((resolve, recject) => {
      // 只接受函数类型，其它类型忽略
      onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (val) => val
      onRejected =
        typeof onRejected === 'function'
          ? onRejected
          : (error) => {
              throw error
            }

      if (this.PromiseState === FULFILLED) {
        // 异步拿到里面的promise
        queueMicrotask(() => {
          try {
            const result = onFulfilled(this.PromiseResult)
            resolvePromise(promise, result, resolve, recject)
          } catch (error) {
            recject(error)
          }
        })
      } else if (this.PromiseState === RECJECTED) {
        queueMicrotask(() => {
          try {
            const result = onRejected(this.PromiseResult)
            resolvePromise(promise, result, resolve, recject)
          } catch (error) {
            recject(error)
          }
        }, 0)
      } else {
        // 存储多个回调
        this.fulfilledCallback.push(() => {
          queueMicrotask(() => {
            try {
              const result = onFulfilled(this.PromiseResult)
              resolvePromise(promise, result, resolve, recject)
            } catch (error) {
              recject(error)
            }
          })
        })
        this.rejectedCallback.push(() => {
          queueMicrotask(() => {
            try {
              const result = onRejected(this.PromiseResult)
              resolvePromise(promise, result, resolve, recject)
            } catch (error) {
              recject(error)
            }
          })
        })
      }
    })

    return promise
  }

  catch(rejected) {
    return this.then(undefined, rejected)
  }

  finally(callback) {
    return this.then(
      (res) => {
        return _Promise.resolve(callback()).then(() => res)
      },
      (err) => {
        return _Promise.reject(callback()).then(() => err)
      }
    )
  }

  static all(arr) {
    const results = []
    let index = 0
    return new _Promise((resolve, recject) => {
      function addResult(key, value) {
        results[key] = value
        index++
        // 根据index判断所有的结果是否都完成
        if (index === arr.length) {
          resolve(results)
        }
      }
      for (let i = 0; i < arr.length; i++) {
        const target = arr[i]
        // promise对象
        if (target instanceof _Promise) {
          target.then(
            (val) => addResult(i, val),
            (error) => recject(error)
          )
        } else {
          addResult(i, target)
        }
      }
    })
  }

  static resolve(value) {
    if (value instanceof _Promise) return value
    return new _Promise((resolve) => resolve(value))
  }

  static reject(error) {
    if (error instanceof _Promise) return error
    return new _Promise((_, recject) => recject(error))
  }
}

function resolvePromise(promise, x, resolve, reject) {
  // 如果相等了，说明return的是自己，抛出类型错误并返回
  if (promise === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }

  if (typeof x === 'object' || typeof x === 'function') {
    // x 为 null 直接返回，走后面的逻辑会报错
    if (x === null) {
      return resolve(x)
    }

    let then
    try {
      // 把 x.then 赋值给 then
      then = x.then
    } catch (error) {
      // 如果取 x.then 的值时抛出错误 error ，则以 error 为据因拒绝 promise
      return reject(error)
    }

    // 如果 then 是函数
    if (typeof then === 'function') {
      let called = false
      try {
        then.call(
          x, // this 指向 x
          // 如果 resolvePromise 以值 y 为参数被调用，则运行 [[Resolve]](promise, y)
          (y) => {
            // 如果 resolvePromise 和 rejectPromise 均被调用，
            // 或者被同一参数调用了多次，则优先采用首次调用并忽略剩下的调用
            // 实现这条需要前面加一个变量 called
            if (called) return
            called = true
            resolvePromise(promise, y, resolve, reject)
          },
          // 如果 rejectPromise 以据因 r 为参数被调用，则以据因 r 拒绝 promise
          (r) => {
            if (called) return
            called = true
            reject(r)
          }
        )
      } catch (error) {
        // 如果调用 then 方法抛出了异常 error：
        // 如果 resolvePromise 或 rejectPromise 已经被调用，直接返回
        if (called) return

        // 否则以 error 为据因拒绝 promise
        reject(error)
      }
    } else {
      // 如果 then 不是函数，以 x 为参数执行 promise
      resolve(x)
    }
  } else {
    // 如果 x 不为对象或者函数，以 x 为参数执行 promise
    resolve(x)
  }
}

// function resolvePromise(promise, result, resolve, recject) {
//   if (promise === result) {
//     return recject(new TypeError('Chaining cycle detected for promise #<Promise>'))
//   }
//   // 返回的是promise
//   if (result instanceof _Promise) {
//     result.then(resolve, recject)
//   } else {
//     // 普通值
//     resolve(result)
//   }
// }

// !! 存在问题
_Promise
  .resolve()
  .then(() => {
    console.log(0)
    return _Promise.resolve(4)
  })
  .then((res) => {
    console.log(res)
  })

_Promise
  .resolve()
  .then(() => {
    console.log(1)
  })
  .then(() => {
    console.log(2)
  })
  .then(() => {
    console.log(3)
  })
  .then(() => {
    console.log(5)
  })
  .then(() => {
    console.log(6)
  })

export default {}
